// Package ioc
/**
* @Project : geektime-basic-go-study
* @File    : db.go
* @IDE     : GoLand
* @Author  : Tvux
* @Date    : 2024/10/7 22:25
**/

package ioc

import (
	"geektime-basic-go-study/webook/backend/config"
	"geektime-basic-go-study/webook/backend/internal/repository/dao"
	"github.com/HJH0924/GenericGo/logger"
	"github.com/spf13/viper"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	glogger "gorm.io/gorm/logger"
	"time"
)

// InitDB
// 连接数据库、建表
func InitDB(zl logger.Logger) *gorm.DB {
	// 数据库连接地址怎么写？
	// refer: https://github.com/go-sql-driver/mysql#dsn-data-source-name
	//db, err := gorm.Open(mysql.Open(viper.GetString("config.dbConf.dsn")))
	// 下面这种读取配置的方式也可以，更推荐
	// 将默认值的设置放到这里，而不是使用 viper.SetDault
	dbConf := config.DbConfig{
		DSN:                  "root:root@tcp(localhost:13316)/webook",
		ParameterizedQueries: true,
	}
	if err := viper.UnmarshalKey("config.dbConf", &dbConf); err != nil {
		panic(err)
	}
	db, err := gorm.Open(mysql.Open(dbConf.DSN), &gorm.Config{
		Logger: glogger.New(gormLoggerFunc(zl.Debug), glogger.Config{
			// 慢查询阈值，只有执行时间超过这个阈值，才会使用
			// 50ms，100ms都是比较合理的慢查询阈值
			// 因为 SQL 查询必然要求命中索引，最好就是走一次磁盘IO
			// 而一次磁盘IO是不到10ms的
			SlowThreshold:        time.Millisecond * 50,
			Colorful:             true,
			ParameterizedQueries: dbConf.ParameterizedQueries, // 这个配置比较消耗资源，生产环境设置为false
			LogLevel:             glogger.Info,
		}),
	})
	if err != nil {
		// 只在初始化过程中 panic
		// panic 相当于整个 goroutine 结束
		// 一旦应用在初始化过程中出错，应用就不要启动了
		panic(err)
	}

	db = db.Debug() // for debug

	// 初始化表
	err = dao.InitTables(db)
	if err != nil {
		panic(err)
	}

	return db
}

// gorm的日志需要传入一个 writer
// 这个 writer 是一个单方法的接口，这里有一个小技巧，但只有单方法的接口才能这样用
type gormLoggerFunc func(msg string, fields ...logger.Field)

func (fn gormLoggerFunc) Printf(msg string, args ...any) {
	fn(msg, logger.Field{Key: "args", Val: args})
}
